/*    Copyright 2010 Tobias Marschall
 *
 *    This file is part of MoSDi.
 *
 *    MoSDi is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    MoSDi is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with MoSDi.  If not, see <http://www.gnu.org/licenses/>.
 */

package mosdi.tests;

import java.util.Arrays;

import junit.framework.TestCase;
import mosdi.discovery.ParetoSet;
import mosdi.discovery.SolutionCandidate;

public class ParetoSetTest extends TestCase {
	
	private class Solution1D implements SolutionCandidate {
		private String name;
		private double score;
		public Solution1D() {
			this.name = "";
			this.score = Double.NaN;
		}
		public Solution1D(String name, double score) {
			this.name = name;
			this.score = score;
		}
		@Override
		public int getObjectiveCount() { return 1; }
		@Override
		public double getObjectiveScore(int objectiveNumber) { return score; }
		@Override
		public String toString() { return Double.toString(score); }
		@Override
		public int compareTo(SolutionCandidate o) {
			if (!(o instanceof Solution1D)) throw new IllegalArgumentException();
			return name.compareTo(((Solution1D)o).name);
		}
		@Override
		public boolean equals(Object o) {
			if (!(o instanceof Solution1D)) return false;
			return name.equals(((Solution1D)o).name);
		}
	}
	
	public void testParetoSet1D() {
		ParetoSet<Solution1D> p = new ParetoSet<Solution1D>(1);
		try {
			p.dominationThreshold(new Solution1D("Test",0.4));
			fail("Exception expected.");
		} catch (IllegalArgumentException e) {}
		assertTrue(p.dominationThreshold(new Solution1D())==Double.NEGATIVE_INFINITY);
		p.update(new Solution1D("Solution1", 1.5));
		assertTrue(p.dominationThreshold(new Solution1D())==1.5);
		p.update(new Solution1D("Solution2", 0.5));
		assertTrue(p.dominationThreshold(new Solution1D())==1.5);
		p.update(new Solution1D("Solution3", 18.5));
		assertTrue(p.dominationThreshold(new Solution1D())==18.5);
		p.update(new Solution1D("Solution4", 10.5));
		assertTrue(p.dominationThreshold(new Solution1D())==18.5);
		assertEquals(1,p.getParetoSet().size());
		assertEquals("Solution3",p.getParetoSet().iterator().next().name);
		p.update(new Solution1D("Solution5", 18.5));
		assertTrue(p.dominationThreshold(new Solution1D())==18.5);
		assertEquals(2,p.getParetoSet().size());
		assertFalse(p.isDominated(new Solution1D("t1",18.5)));
		assertFalse(p.isDominated(new Solution1D("t2",18.51)));
		assertTrue(p.isDominated(new Solution1D("t3",18.49)));
	}
	
	private class Solution2D implements SolutionCandidate {
		private String name;
		private double[] scores;
		public Solution2D(String name, double score1, double score2) {
			this.name = name;
			double[] d = {score1, score2};
			this.scores = d;
		}
		public Solution2D(double score1) {
			this.name = "Unnamed_"+score1;
			double[] d = {score1, Double.NaN};
			this.scores = d;
		}
		@Override
		public int getObjectiveCount() { return 2; }
		@Override
		public double getObjectiveScore(int objectiveNumber) { return scores[objectiveNumber]; }
		@Override
		public String toString() { return Arrays.toString(scores); }
		@Override
		public int compareTo(SolutionCandidate o) {
			if (!(o instanceof Solution2D)) throw new IllegalArgumentException();
			return name.compareTo(((Solution2D)o).name);
		}
		@Override
		public boolean equals(Object o) {
			if (!(o instanceof Solution2D)) return false;
			return name.equals(((Solution2D)o).name);
		}
	}

	public void testParetoSet2D() {
		ParetoSet<Solution2D> p = new ParetoSet<Solution2D>(2);
		assertEquals(0,p.getParetoSet().size());
		
		Solution2D s1 = new Solution2D("Solution1", 0.5, 4.0); 
		Solution2D s2 = new Solution2D("Solution2", 1.5, 3.0); 
		Solution2D s3 = new Solution2D("Solution3", 7.0, 3.5); 
		Solution2D s4 = new Solution2D("Solution4", 10.5, 18.3); 
		Solution2D s5 = new Solution2D("Solution5", 12.5, 15.3); 
		Solution2D s6 = new Solution2D("Solution6", 10.5, 18.0); 
		Solution2D s7 = new Solution2D("Solution7", 10.5, 18.4); 
		Solution2D s8 = new Solution2D("Solution8", 12.4, 15.3); 
		Solution2D s9 = new Solution2D("Solution9", 12.6, 15.3); 
		Solution2D s10 = new Solution2D("Solution10", 12.6, 15.3);

		p.update(s1);
		assertEquals(1,p.getParetoSet().size());
		assertTrue(p.getParetoSet().contains(s1));
		assertTrue(p.dominationThreshold(new Solution2D(0.5))==4.0);
		assertTrue(p.dominationThreshold(new Solution2D(0.51))==Double.NEGATIVE_INFINITY);
		assertTrue(p.dominationThreshold(new Solution2D(0.49))==4.0);
		p.update(s2);
		assertEquals(2,p.getParetoSet().size());
		assertTrue(p.getParetoSet().contains(s1));
		assertTrue(p.getParetoSet().contains(s2));
		p.update(s3);
		assertEquals(2,p.getParetoSet().size());
		assertTrue(p.getParetoSet().contains(s1));
		assertFalse(p.getParetoSet().contains(s2));
		assertTrue(p.getParetoSet().contains(s3));
		p.update(s4);
		assertEquals(1,p.getParetoSet().size());
		assertTrue(p.getParetoSet().contains(s4));
		p.update(s5);
		assertEquals(2,p.getParetoSet().size());
		assertTrue(p.getParetoSet().contains(s4));
		assertTrue(p.getParetoSet().contains(s5));
		p.update(s6);
		assertEquals(2,p.getParetoSet().size());
		assertTrue(p.getParetoSet().contains(s4));
		assertTrue(p.getParetoSet().contains(s5));
		p.update(s7);
		assertEquals(2,p.getParetoSet().size());
		assertTrue(p.getParetoSet().contains(s5));
		assertTrue(p.getParetoSet().contains(s7));
		assertTrue(p.dominationThreshold(new Solution2D(8.0))==18.4);
		assertTrue(p.dominationThreshold(new Solution2D(10.5))==18.4);
		assertTrue(p.dominationThreshold(new Solution2D(10.51))==15.3);
		assertTrue(p.dominationThreshold(new Solution2D(12.5))==15.3);
		assertTrue(p.dominationThreshold(new Solution2D(12.51))==Double.NEGATIVE_INFINITY);
		p.update(s8);
		assertEquals(2,p.getParetoSet().size());
		assertTrue(p.getParetoSet().contains(s5));
		assertTrue(p.getParetoSet().contains(s7));
		p.update(s9);
		assertEquals(2,p.getParetoSet().size());
		assertTrue(p.getParetoSet().contains(s7));
		assertTrue(p.getParetoSet().contains(s9));
		p.update(s10);
		assertEquals(3,p.getParetoSet().size());
		assertTrue(p.getParetoSet().contains(s7));
		assertTrue(p.getParetoSet().contains(s9));
		assertTrue(p.getParetoSet().contains(s10));
		assertFalse(p.isDominated(new Solution2D("",10.5,18.4)));
		assertFalse(p.isDominated(new Solution2D("",10.5,18.5)));
		assertFalse(p.isDominated(new Solution2D("",10.6,18.4)));
		assertTrue(p.isDominated(new Solution2D("",10.5,18.3)));
		assertTrue(p.isDominated(new Solution2D("",10.4,18.4)));
		assertFalse(p.isDominated(new Solution2D("",12.6,15.3)));
		assertFalse(p.isDominated(new Solution2D("",12.6,15.4)));
		assertFalse(p.isDominated(new Solution2D("",12.7,15.3)));
		assertFalse(p.isDominated(new Solution2D("",12.7,15.4)));
		assertTrue(p.isDominated(new Solution2D("",12.5,15.3)));
		assertTrue(p.isDominated(new Solution2D("",12.6,15.2)));
		assertTrue(p.isDominated(new Solution2D("",12.5,15.2)));
		assertTrue(p.isDominated(new Solution2D("",1.0,1.3)));
	}

}
